package com.shuimin.service.service.sys;

import com.shuimin.service.AccessDeniedException;
import com.shuimin.service.App;
import com.shuimin.service.model.sys.Shop;
import com.shuimin.service.model.sys.User;
import pond.common.S;
import pond.common.STRING;
import pond.common.struc.Cache;
import pond.db.JDBCTmpl;
import pond.db.Record;
import pond.db.sql.Criterion;
import pond.db.sql.Sql;
import pond.db.sql.SqlSelect;
import pond.security.rbac.RBAC;
import pond.web.EndToEndException;

import java.util.List;

/**
 * Created by ed on 12/24/15.
 */
public class UserService {

    public static List<User> all(JDBCTmpl t) {
        S._assertNotNull(t);
        SqlSelect select = Sql.select("*").from(User.class);
        if (!App.currentRoles().hasAny(SysRoles.Roles.QUERY_ACROSS_SHOPS.id)) {
            select.where("shop_id", Criterion.EQ, App.currentUser().shop().id());
        }
        return t.query(User.class, select);
    }

    /**
     * +-----------+--------------+------+-----+---------+-------+
     * | Field     | Type         | Null | Key | Default | Extra |
     * +-----------+--------------+------+-----+---------+-------+
     * | id        | varchar(64)  | NO   |     | NULL    |       |
     * | name      | varchar(255) | YES  |     | NULL    |       |
     * | uid       | varchar(255) | YES  |     | NULL    |       |
     * | rank      | varchar(40)  | YES  |     | NULL    |       |
     * | shop_id   | varchar(64)  | YES  |     | NULL    |       |
     * | shop_name | varchar(64)  | YES  |     | NULL    |       |
     * +-----------+--------------+------+-----+---------+-------+
     */
    public static List<Record> brief(JDBCTmpl t) {
        S._assertNotNull(t);
        SqlSelect select = Sql.select("*").from("v_user_brief");
        if (!App.currentRoles().hasAny(SysRoles.Roles.QUERY_ACROSS_SHOPS.id)) {
            select.where("shop_id", Criterion.EQ, App.currentUser().shop().id());
        }
        return t.query(select);
    }

    private static Cache<String, User> cache = Cache.lruCache(1000);

    public static User getUserByUid(String uid) {
        return cache.get(uid, c -> {
            List<User> users = App.DB.get(t -> t.recordsQuery(User.class, "uid", Criterion.EQ, uid));
            if (users.size() < 1)
                return null;
            return users.get(0).refineViewShops().refineRoles().refineShop();
        });
    }


    public static List<User> getUserByUidOrName(String param) {
        return App.DB.get(t -> t.query(User.class, "SELECT * FROM t_user WHERE uid like '%" + param + "%' OR name like '%" + param + "%'"));
    }

    public static List<User> getByShop(String shop_id) {
        return App.DB.get(t -> t.query(User.class, "SELECT * FROM t_user WHERE shop_id = ?", shop_id));
    }

    public static List<Record> salesmenForCurShop(JDBCTmpl t) {
        String sql = "select v.*, rr.id as role_id, rr.rolename " +
                "from v_user_brief v " +
                " left join rbac_user_has_role r" +
                " on v.id = r.user_id" +
                " left join rbac_role rr" +
                " on r.role_id = rr.id where r.role_id = ?";
        if (App.currentRoles().hasNone(SysRoles.Roles.MANAGE_ACROSS_SHOPS.id)) {
            sql += " and v.shop_id = ?";
            return t.query(sql, SysRoles.Roles.HR_SALESMAN_MARK.id, App.currentUser().shop().id());
        }
        return t.query(sql, SysRoles.Roles.HR_SALESMAN_MARK.id);
    }

    //TODO refactor this with ShopFilter
    public static List<Record> salesmenForShop(String shop_id, JDBCTmpl t) {
        if (STRING.isBlank(shop_id)) {
            return salesmenForCurShop(t);
        }
        String sql = "select v.*, rr.id as role_id, rr.rolename " +
                "from v_user_brief v " +
                " left join rbac_user_has_role r" +
                " on v.id = r.user_id" +
                " left join rbac_role rr" +
                " on r.role_id = rr.id where r.role_id = ?";
        if (App.currentRoles().hasAny(SysRoles.Roles.MANAGE_ACROSS_SHOPS.id,
                SysRoles.Roles.QUERY_ACROSS_SHOPS.id,
                SysRoles.Roles.QUERY_ACROSS_SHOPS_FOR_BRAND.id)) {

            sql += " and v.shop_id = ?";
            return t.query(sql, SysRoles.Roles.HR_SALESMAN_MARK.id, shop_id);
        } else {
            sql += " and v.shop_id = ?";
            return t.query(sql, SysRoles.Roles.HR_SALESMAN_MARK.id, App.currentUser().shop().id());
        }

    }

    //TODO refactor this with ShopFilter
    public static List<Record> evaluator(String shop_id, JDBCTmpl t) {

        String sql = "select v.*, rr.id as role_id, rr.rolename " +
                "from v_user_brief v " +
                " left join rbac_user_has_role r" +
                " on v.id = r.user_id" +
                " left join rbac_role rr" +
                " on r.role_id = rr.id where r.role_id = ?";
        if (!STRING.isBlank(shop_id)) {
            sql += " and v.shop_id = '" + shop_id + "'";
        }

        //如果是评估师,那么该员工只能查询出自己? ADMIN?
        if (App.currentRoles().hasAny(SysRoles.Roles.HR_EVALUATOR_MARK.id)) {
            sql += String.format(" AND v.id = '%s'", App.currentUser().id());
        }

        return t.query(sql, SysRoles.Roles.HR_EVALUATOR_MARK.id );

    }

//  public static void addSalesmenToCurShop(JDBCTmpl t) { }
//  public static void removeSalesmenForCurShop(JDBCTmpl t) { }

    /**
     * 查询出所有没有门店的用户
     *
     * @return
     */
    public static List<User> getUserWithoutShop() {

        if (App.currentRoles().hasAny(SysRoles.Roles.HR_USER_MGMT.id,
                SysRoles.Roles.MANAGE_ACROSS_SHOPS.id)) {
            return App.DB.get(t -> t.query(User.class, "SELECT * FROM t_user WHERE shop_id is null OR shop_id=''"));
        } else
            throw new AccessDeniedException(SysRoles.Roles.HR_USER_MGMT, SysRoles.Roles.MANAGE_ACROSS_SHOPS);
    }

    public static void addUser(User user, JDBCTmpl t) {
        RBAC.Roles roles = App.currentRoles();
        if (roles.hasAny(SysRoles.Roles.HR_USER_MGMT.id)) {
            S._assert(user.get("uid"));
            String shop_id = user.get("shop_id");
            if (shop_id == null) throw new EndToEndException(400, "添加用户时请选择门店");
            if (shop_id.equals(App.currentUser().shop().id())
                    || roles.hasAny(SysRoles.Roles.MANAGE_ACROSS_SHOPS.id)) {
                t.recordInsert(user);
                cache.put(user.get("uid"), user);
            } else {
                throw new AccessDeniedException(SysRoles.Roles.MANAGE_ACROSS_SHOPS);
            }
            cache.put(user.get("uid"), user);
        } else throw new AccessDeniedException();

    }

    public static void clearViewShops(User user, JDBCTmpl t) {
        t.exec("delete from r_user_view_shop where user = ?", user.id());
    }

    public static void addViewShops(User user, String[] viewShops, JDBCTmpl t) {
        for (String v : viewShops)
            t.exec("insert into r_user_view_shop values(?,?)", user.id(), v);
    }

    public static void delUser(User user, JDBCTmpl t) {
        if (App.currentRoles().hasAny(SysRoles.Roles.HR_USER_MGMT.id)) {
            if (user.id() != null && user.id().equals(App.currentUser().id()))
                throw new AccessDeniedException("你确定要干掉自己吗");
            if (App.rbac.forUser(user.id()).hasAny(SysRoles.Roles.SUPER_ADMIN.id)) {
                throw new AccessDeniedException("请先解除用户权限: " + SysRoles.Roles.SUPER_ADMIN.id);
            }
            if (App.rbac.forUser(user.id()).hasAny(SysRoles.Roles.HR_USER_MGMT.id)) {
                throw new AccessDeniedException("请先解除所选用户超管权限");
            }
            t.recordDelete(user);
            cache.remove(user.get("uid"));
        } else throw new AccessDeniedException();

    }

    public static void updUser(User user, JDBCTmpl t) {
        RBAC.Roles roles = App.currentRoles();
        if (roles.hasAny(SysRoles.Roles.HR_USER_MGMT.id)) {
            if (t.recordExists(User.class, user.id())) {
                S._assert(user.get("uid"));
                if (user.shop().id().equals(App.currentUser().shop().id())
                        || roles.hasAny(SysRoles.Roles.MANAGE_ACROSS_SHOPS.id)) {
                    t.recordUpdate(user);
                    cache.put(user.get("uid"), user);
                } else {
                    throw new AccessDeniedException(SysRoles.Roles.MANAGE_ACROSS_SHOPS);
                }
            } else throw new RuntimeException("" + user + " does not exist");
        } else throw new AccessDeniedException();
    }

    public static List<Record> briefForRole() {
        return App.DB.get("SELECT id, name FROM t_user");
    }

    public static void updShopForUser(User user, Shop shop) {
        RBAC.Roles roles = App.currentRoles();
        if (roles.hasAny(SysRoles.Roles.HR_USER_MGMT.id)) {
            if (shop.id().equals(App.currentUser().shop().id())) {
                user.shop(shop);
            } else if (roles.hasAny(SysRoles.Roles.MANAGE_ACROSS_SHOPS.id)) {
                user.shop(shop);
            } else {
                throw new AccessDeniedException(SysRoles.Roles.MANAGE_ACROSS_SHOPS);
            }
            App.DB.post(t -> t.recordUpdate(user));
        } else throw new AccessDeniedException(SysRoles.Roles.HR_USER_MGMT);
    }

    public static void delShopForUser(User user) {
        if (App.currentRoles().hasAny(SysRoles.Roles.HR_USER_MGMT.id,
                SysRoles.Roles.MANAGE_ACROSS_SHOPS.id)) {
            user.resetShop();
            App.DB.post(t -> t.recordUpdate(user));
        } else throw new AccessDeniedException();
    }

}
